package com.nan.bytecode.asm;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.AdviceAdapter;

import java.io.IOException;

public class AOPTrack {
    private final static String MONITOR_API = "com/nan/bytecode/MonitorLog";

    public static byte[] track() throws IOException {
        ClassReader classReader = new ClassReader(UserModel.class.getName());
        ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);
        ClassVisitor classVisitor = new TrackClassVisitor(classWriter);
        classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
        return classWriter.toByteArray();
    }

    static class TrackClassVisitor extends ClassVisitor {
        public TrackClassVisitor(ClassVisitor classVisitor) {
            super(Opcodes.ASM7, classVisitor);
        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
            MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
            return new TrackMethodVisitor(methodVisitor, access, name, descriptor);
        }
    }

    static class TrackMethodVisitor extends AdviceAdapter {
        private String name;

        protected TrackMethodVisitor(MethodVisitor methodVisitor, int access, String name, String descriptor) {
            super(ASM7, methodVisitor, access, name, descriptor);
            this.name = name;
        }

        @Override
        protected void onMethodEnter() {
            mv.visitLdcInsn(name);
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, MONITOR_API, "track", "(Ljava/lang/String;)V", false);
        }
    }
}
